/* eslint-disable prefer-const */
/* eslint-disable no-var */
import * as xlsx from "xlsx";
import type { WorkBook } from "xlsx";
import { JsonToSheet, AoAToSheet } from "./typing.ts";
import XLSXStyle from "xlsx-style-vite";
import XLSX_SAVE from "file-saver";
import { isEmptyString } from "@/utils/is";

const { utils, writeFile } = xlsx;

const DEF_FILE_NAME = "excel-list.xlsx";

export function jsonToSheetXlsx<T = any>({
  data,
  header,
  filename = DEF_FILE_NAME,
  json2sheetOpts = {},
  write2excelOpts = { bookType: "xlsx" },
}: JsonToSheet<T>) {
  const arrData = [...data];
  if (header) {
    arrData.unshift(header);
    json2sheetOpts.skipHeader = true;
  }

  const worksheet = utils.json_to_sheet(arrData, json2sheetOpts);

  /* add worksheet to workbook */
  const workbook: WorkBook = {
    SheetNames: [filename],
    Sheets: {
      [filename]: worksheet,
    },
  };
  /* output format determined by filename */
  writeFile(workbook, filename, write2excelOpts);
  /* at this point, out.xlsb will have been downloaded */
}

export function aoaToSheetXlsx<T = any>({
  data,
  header,
  headerData,
  filename = DEF_FILE_NAME,
  write2excelOpts = { bookType: "xlsx" },
  merges = [],
}: AoAToSheet<T>) {
  const arrData = [...data];
  const hasHeaderTitle = headerData && filename != DEF_FILE_NAME;

  if (headerData?.list) {
    arrData.unshift(...headerData.list);

    // 根据导出文件名称生成表头
    if (filename != DEF_FILE_NAME) {
      const headerTitle: any[] = [];
      headerData.list?.[0]?.forEach(() => {
        headerTitle.push(filename);
      });
      arrData.unshift(headerTitle);

      // 表格内容合并信息修正
      merges.forEach((item) => {
        item.s = { r: item.s.r + headerData.maxDepth, c: item.s.c };
        item.e = { r: item.e.r + headerData.maxDepth, c: item.e.c };
      });
      merges.push({
        s: { r: 0, c: 0 },
        e: { r: 0, c: headerData.list?.[0]?.length - 1 },
      });
      // 表格标题合并信息
      merges.push(...headerData.merges);
    }
  }

  const worksheet = utils.aoa_to_sheet(arrData);

  /* add worksheet to workbook */
  const workbook: WorkBook = {
    SheetNames: [filename],
    Sheets: {
      [filename]: worksheet,
    },
  };

  // 设置列宽
  arrData.forEach((row, rowIndex) => {
    row.forEach((cell, cellIndex) => {
      const list = arrData.map((item, index) => {
        if (hasHeaderTitle && index === 0) return 1; // 表头行不设置列宽
        if (hasHeaderTitle && index >= 1 && index <= headerData.maxDepth)
          return 1; // 表头行不设置列宽

        const val = item[cellIndex] as string;
        if (isEmptyString(val)) {
          return 1;
        } else if (val.toString().charCodeAt(0) > 255) {
          // 判断是否有中文
          return val.toString().length * 2;
        } else {
          return val.toString().length;
        }
      });
      const maxLength = Math.max(...list);
      const width = maxLength < 8 ? 8 : maxLength * 1.1; // 根据实际内容长度自动调整列宽
      if (!worksheet["!cols"]) worksheet["!cols"] = [];
      if (!worksheet["!cols"][cellIndex])
        worksheet["!cols"][cellIndex] = { wch: 8 };
      worksheet["!cols"][cellIndex].wch = width; // 使用worksheet的 '!cols' 来设置列宽

      // 设置所有单元格样式
      let column = utils.encode_cell({ c: cellIndex, r: rowIndex });
      if (!worksheet[column]) worksheet[column] = { v: "" };
      // 表头行设置背景色、加粗展示
      if (hasHeaderTitle && rowIndex === 0) {
        worksheet[column].s = getHeaderTitleStyle();
      }
      // 标题行设置背景色、加粗展示
      else if (
        (!hasHeaderTitle && rowIndex === 0) ||
        (hasHeaderTitle && rowIndex >= 1 && rowIndex <= headerData.maxDepth)
      ) {
        worksheet[column].s = getHeaderStyle();
      } else {
        worksheet[column].s = getDefaultCellStyle();
      }
    });
  });

  // 合并单元格
  merges.forEach((item) => {
    if (!worksheet["!merges"]) {
      worksheet["!merges"] = [];
    }
    worksheet["!merges"].push(item);
    // worksheet["!merges"].push({
    //   s: { r: 2, c: 1 }, // s ("start"): c = 1 r = 2 -> "B3"
    //   e: { r: 3, c: 4 }  // e ("end"):   c = 4 r = 3 -> "E4"
    // });
  });

  const wbout = XLSXStyle.write(workbook, {
    type: "binary",
    bookType: "xlsx",
  });
  XLSX_SAVE.saveAs(
    new Blob([s2ab(wbout)], {
      type: "application/octet-stream",
    }),
    `${filename}.${write2excelOpts.bookType}`
  );

  /* output format determined by filename */
  // writeFile(workbook, filename, write2excelOpts);
  /* at this point, out.xlsb will have been downloaded */
}

// 数据转换
function s2ab(s) {
  var buf = new ArrayBuffer(s.length);
  var view = new Uint8Array(buf);
  for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
  return buf;
}

//单元格外侧框线
const borderAll = {
  top: {
    style: "thin",
  },
  bottom: {
    style: "thin",
  },
  left: {
    style: "thin",
  },
  right: {
    style: "thin",
  },
};

// 获取表头样式
const getHeaderTitleStyle = () => ({
  // border: borderAll,
  font: {
    name: "微软雅黑",
    sz: 16,
    color: { rgb: "000000" },
    bold: true,
    italic: false,
    underline: false,
  },
  fill: {
    fgColor: { rgb: "D0D0D0" },
  },
  alignment: {
    horizontal: "center",
    vertical: "center",
    wrapText: false, // 自动换行
  },
});

// 获取标题样式
const getHeaderStyle = () => ({
  border: borderAll,
  font: {
    // name: "微软雅黑",
    // sz: 16,
    color: { rgb: "000000" },
    bold: true,
    italic: false,
    underline: false,
  },
  fill: {
    fgColor: { rgb: "C5D9F1" },
  },
  alignment: {
    horizontal: "center",
    vertical: "center",
    wrapText: false, // 自动换行
  },
});

// 获取默认单元格样式
const getDefaultCellStyle = () => ({
  border: borderAll,
  alignment: {
    horizontal: "center",
    vertical: "center",
    wrapText: false, // 自动换行
  },
});
